home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / dvibook / Dvitodvi / dvitodvi.c < prev    next >
C/C++ Source or Header  |  1994-03-18  |  26KB  |  1,142 lines

  1. /*
  2.  * Copyright (c) 1987, 1989 University of Maryland
  3.  * Department of Computer Science.  All rights reserved.
  4.  * Permission to copy for any purpose is hereby granted
  5.  * so long as this copyright notice remains intact.
  6.  */
  7.  
  8. #ifndef lint
  9. static char rcsid[] = "$Header: /usr/src/local/tex/local/mctex/dvi/RCS/dviselect.c,v 3.1 89/08/22 17:16:13 chris Exp $";
  10. #endif
  11.  
  12. /*
  13.  * DVI page rearrangement program
  14.  *
  15.  * Reads DVI version 2 files and rearranges pages,
  16.  * writing a new DVI file.
  17.  */
  18.  
  19. #include "libtex/types.h"
  20. #include "libtex/dviclass.h"
  21. #include "libtex/dvicodes.h"
  22. #include "libtex/error.h"
  23. #include "libtex/fio.h"
  24. #include "libtex/gripes.h"
  25. #include "libtex/search.h"
  26. #include <stdio.h>
  27. #include <ctype.h>
  28. #include "libtex/seek.h"
  29.  
  30. #define white(x) ((x) == ' ' || (x) == '\t' || (x) == ',')
  31.  
  32. #define MAXDVIPAGES 1000 /* max (absolute) pages in DVI file */
  33.  
  34. char  *ProgName;
  35. extern char *optarg;
  36. extern int   optind;
  37.  
  38. /* Globals */
  39. char    serrbuf[BUFSIZ];    /* buffer for stderr */
  40.  
  41. /*
  42.  * We will try to keep output lines shorter than MAXCOL characters.
  43.  */
  44. #define MAXCOL    75
  45.  
  46. /*
  47.  * We use the following structure to keep track of fonts we have seen.
  48.  * The final DVI file lists only the fonts it uses.
  49.  */
  50. struct fontinfo {
  51.     i32    fi_newindex;    /* font number in output file */
  52.     int    fi_reallyused;    /* true => used on a page we copied */
  53.     i32    fi_checksum;    /* the checksum */
  54.     i32    fi_mag;        /* the magnification */
  55.     i32    fi_designsize;    /* the design size */
  56.     short    fi_n1;        /* the name header length */
  57.     short    fi_n2;        /* the name body length */
  58.     char    *fi_name;    /* the name itself */
  59. };
  60.  
  61.  
  62. i32     Width;                  /* width of page */
  63. i32     Height;                 /* height of page */
  64. i32     Magnification;          /* Magnification of pages */
  65. int     Modulo;                 /* page spec modulo */
  66. struct pagespec *PageSpecs;     /* page specification list */
  67.  
  68. int    SFlag;            /* true => -s, silent operation */
  69.  
  70. struct    search *FontFinder;    /* maps from input indicies to fontinfo */
  71. i32    NextOutputFontIndex;    /* generates output indicies */
  72. i32    CurrentFontIndex;    /* current (old) index in input */
  73. i32    OutputFontIndex;    /* current (new) index in ouput */
  74.  
  75. char    *DVIFileName;        /* name of input DVI file */
  76. FILE    *inf;            /* the input file itself */
  77. FILE    *outf;            /* the output DVI file */
  78.  
  79. long    StartOfPage[MAXDVIPAGES];    /* The file positions of the
  80.                        input pages */
  81.  
  82. long    StartOfLastPage;    /* The file position just before we
  83.                    started the last page */
  84. long    CurrentPosition;    /* The current position of the file */
  85.  
  86. int    UseThisPage;        /* true => current page is selected */
  87.  
  88. i32    InputPageNumber;    /* current absolute page in old DVI file */
  89. int    NumberOfOutputPages;    /* number of pages in new DVI file */
  90.  
  91. i32    Numerator;        /* numerator from DVI file */
  92. i32    Denominator;        /* denominator from DVI file */
  93. i32    DVIMag;            /* magnification from DVI file */
  94.  
  95. i32    Count[10];        /* the 10 \count variables */
  96.  
  97. /* save some string space: we use this a lot */
  98. char    writeerr[] = "error writing DVI file";
  99.  
  100. char    *malloc(), *realloc();
  101. /*
  102.  * You may get lint warnings about sprintf's return value.
  103.  * Older versions of 4BSD have `char *sprintf()'.  ANSI and
  104.  * SysV use `int sprintf()'; so ignore the warnings.
  105.  */
  106.  
  107. /*
  108.  * Lint gets somewhat confused over putc.
  109.  */
  110. #ifdef lint
  111. #undef putc
  112. #ifdef ultrix /* grr */
  113. #define putc(c, f) fputc((char)(c), f)
  114. #else
  115. #define putc(c, f) fputc((int)(c), f)
  116. #endif
  117. #endif
  118.  
  119. void specusage()
  120. {
  121.    error(1, -1, "page specification error:\n\
  122.   <pagespecs> = [modulo:][mag@]<spec>\n\
  123.   <spec>      = [-]pageno[(xoff,yoff)][,spec|+spec]\n\
  124.                 modulo>=1, 0<=pageno<modulo");
  125. }
  126.  
  127. /*
  128.  *   This function calculates approximately (whole + num/den) * sf.
  129.  *   No need for real extreme accuracy; one ten thousandth of an
  130.  *   inch should be sufficient.
  131.  *
  132.  *   Assumptions:
  133.  *
  134.  *      0 <= num < den <= 10000
  135.  *      0 <= whole
  136.  */
  137. i32 defaultscale = 4736286 ;
  138. i32 scale(whole, num, den, sf)
  139.      i32 whole, sf;
  140.      int num, den;
  141. {
  142.    i32 v ;
  143.  
  144.    if (!sf)
  145.       sf = defaultscale ;
  146.    v = whole * sf + num * (sf / den) ;
  147.    if (v / sf != whole || v < 0 || v > 0x40000000L)
  148.       error(1, -1, "arithmetic overflow in dimension") ;
  149.    sf = sf % den ;
  150.    v += (sf * num * 2 + den) / (2 * den) ;
  151.    return (v) ;
  152. }
  153.  
  154. struct pagespec {
  155.    int reversed, pageno, add;
  156.    i32 xoff, yoff;
  157.    struct pagespec *next;
  158. };
  159.  
  160. struct pagespec *newspec()
  161. {
  162.    struct pagespec *temp = (struct pagespec *)malloc(sizeof(struct pagespec));
  163.    temp->reversed = temp->pageno = temp->add = 0;
  164.    temp->xoff = temp->yoff = 0;
  165.    temp->next = NULL;
  166.    return (temp);
  167. }
  168.  
  169. int parseint(sp)
  170.      char **sp;
  171. {
  172.    char *s = *sp;
  173.    int n = 0, neg = 0;
  174.  
  175.    if (*s == '-') {
  176.       neg = 1;
  177.       s++;
  178.    }
  179.    for (; isdigit(*s); s++)
  180.       n = n*10 + (*s-'0');
  181.    if (*sp == s) specusage();
  182.    *sp = s;
  183.    return (neg ? -n : n);
  184. }
  185.  
  186. i32 parsedimen(sp)
  187.      char **sp;
  188. {
  189.    i32 whole = 0;
  190.    int num = 0, den = 1, neg = 0;
  191.    i32 fac = 0L;
  192.    char *s = *sp;
  193.  
  194.    if (*s == '-') {
  195.       neg = 1;
  196.       *sp = ++s;
  197.    }
  198.    for (; isdigit(*s); s++)
  199.       whole = whole*10 + (*s-'0');
  200.  
  201.    if (*s == '.') {
  202.       *sp = ++s;
  203.       for (; isdigit(*s); s++) {
  204.      if (den < 10000) { /* limit precision for scale to work */
  205.         num = num*10 + (*s-'0');
  206.         den *= 10;
  207.      }
  208.       }
  209.    }
  210.    if (*sp == s) specusage();
  211.    *sp = s;
  212.  
  213.    /*
  214.     *   Allowed units are `in', `cm', `mm', `pt', `sp', `cc', `dd', and `pc';
  215.     *   must be in lower case.
  216.     */
  217.    if (*s == 'c' && s[1] == 'm') {
  218.       /* centimeters need to be scaled by 72.27 * 216 / 2.54, or 1 864 680 */
  219.       fac = 1864680L ;
  220.       s += 2;
  221.    } else if (*s == 'p' && s[1] == 't') {
  222.       /*  real points need to be scaled by 65536 */
  223.       fac = 65536L ;
  224.       s += 2;
  225.    } else if (*s == 'p' && s[1] == 'c') {
  226.       /*  picas need to be scaled by 65536 * 12, or 786 432 */
  227.       fac = 786432L ;
  228.       s += 2;
  229.    } else if (*s == 'm' && s[1] == 'm') {
  230.       /*  millimeters need to be scaled by 72.27 * 216 / 25.4, or 186 468 */
  231.       fac = 186468L ;
  232.       s += 2;
  233.    } else if (*s == 's' && s[1] == 'p') {
  234.       /*  scaled points are already taken care of; simply round */
  235.       fac = 1L ;
  236.       s += 2;
  237.    } else if (*s == 'b' && s[1] == 'p') {
  238.       /*  big points need to be scaled by 72.27 * 65536 / 72, or 65782 */
  239.       fac = 65782L ;
  240.       s += 2;
  241.    } else if (*s == 'd' && s[1] == 'd') {
  242.       /*  didot points need to be scaled by 65536 * 1238 / 1157, or 70124 */
  243.       fac = 70124L ;
  244.       s += 2;
  245.    } else if (*s == 'c' && s[1] == 'c') {
  246.       /*  cicero need to be scaled by 65536 * 1238 / 1157 * 12, or 841 489 */
  247.       fac = 841489L ;
  248.       s += 2;
  249.    } else if (*s == 'i' && s[1] == 'n') {
  250.       /*  inches need to be scaled by 72.27 * 65536, or 4 736 286 */
  251.       fac = 4736286L ;
  252.       s += 2;
  253.    } else if (*s == 'w') {
  254.       fac = Width;
  255.       s++;
  256.    } else if (*s == 'h') {
  257.       fac = Height;
  258.       s++;
  259.    }
  260.    whole = scale(whole, num, den, fac) ;
  261.    *sp = s;
  262.    return (neg ? -whole : whole);
  263. }
  264.  
  265. struct pagespec *ParseSpecs(str, make)
  266.      char *str;
  267.      int make;
  268. {
  269.    char *t;
  270.    struct pagespec *head, *tail;
  271.    int other = 0;
  272.    int num = -1;
  273.    struct pagespec spare;
  274.  
  275.    if (make)
  276.       head = tail = newspec();
  277.    else
  278.       head = tail = &spare;
  279.    while (*str) {
  280.       if (isdigit(*str)) {
  281.      num = parseint(&str);
  282.       } else {
  283.      switch (*str++) {
  284.      case ':':
  285.         if (other || head != tail || num < 1) specusage();
  286.         Modulo = num;
  287.         num = -1;
  288.         break;
  289.      case '@':
  290.         if (other || head != tail || num < 1) specusage();
  291.         Magnification = num;
  292.         num = -1;
  293.         break;
  294.      case '-':
  295.         tail->reversed = !tail->reversed;
  296.         other = 1;
  297.         break;
  298.      case '(':
  299.         tail->xoff += parsedimen(&str);
  300.         if (*str++ != ',') specusage();
  301.         tail->yoff += parsedimen(&str);
  302.         if (*str++ != ')') specusage();
  303.         other = 1;
  304.         break;
  305.      case '+':
  306.         tail->add = 1;
  307.      case ',':
  308.         if (num < 0 || num >= Modulo) specusage();
  309.         tail->pageno = num;
  310.         if (make) {
  311.            tail->next = newspec();
  312.            tail = tail->next;
  313.         }
  314.         num = -1;
  315.         other = 1;
  316.         break;
  317.      default:
  318.         specusage();
  319.      }
  320.       }
  321.    }
  322.    if (num >= Modulo)
  323.       specusage();
  324.    else if (num >= 0)
  325.       tail->pageno = num;
  326.    return (head);
  327. }
  328.  
  329. i32 singledimen(str)
  330.      char *str;
  331. {
  332.    i32 num = parsedimen(&str);
  333.    if (*str) return (0);
  334.    return (num);
  335. }
  336.  
  337. /*
  338.  * Print a message to stderr, with an optional leading space, and handling
  339.  * long line wraps.
  340.  */
  341. message(space, str, len)
  342.     int space;
  343.     register char *str;
  344.     register int len;
  345. {
  346.     static int beenhere;
  347.     static int col;
  348.  
  349.     if (!beenhere)
  350.         space = 0, beenhere++;
  351.     if (len == 0)
  352.         len = strlen(str);
  353.     col += len;
  354.     if (space) {
  355.         if (col >= MAXCOL)
  356.             (void) putc('\n', stderr), col = len;
  357.         else
  358.             (void) putc(' ', stderr), col++;
  359.     }
  360.     while (--len >= 0)
  361.         (void) putc(*str++, stderr);
  362.     (void) fflush(stderr);
  363. }
  364.  
  365. /*
  366.  * Start a page (process a DVI_BOP).
  367.  */
  368. BeginPage(really)
  369.      int really;
  370. {
  371.     register i32 *i;
  372.  
  373.     OutputFontIndex = -1;    /* new page requires respecifying font */
  374.     for (i = Count; i < &Count[10]; i++)
  375.         fGetLong(inf, *i);
  376.     (void) GetLong(inf);    /* previous page pointer */
  377.  
  378.     if (!UseThisPage || !really)
  379.         return;
  380.  
  381.     putbyte(outf, DVI_BOP);
  382.     for (i = Count; i < &Count[10]; i++)
  383.         PutLong(outf, *i);
  384.     PutLong(outf, StartOfLastPage);
  385.     if (ferror(outf))
  386.         error(1, -1, writeerr);
  387.  
  388.     StartOfLastPage = CurrentPosition;
  389.     CurrentPosition += 45;    /* we just wrote this much */
  390.  
  391.     if (!SFlag) {        /* write nice page usage messages */
  392.         register int z = 0;
  393.         register int mlen = 0;
  394.         char msg[80];
  395.  
  396.         (void) sprintf(msg, "[%ld", (long)Count[0]);
  397.         mlen = strlen(msg);
  398.         for (i = &Count[1]; i < &Count[10]; i++) {
  399.             if (*i == 0) {
  400.                 z++;
  401.                 continue;
  402.             }
  403.             while (--z >= 0)
  404.                 msg[mlen++] = '.', msg[mlen++] = '0';
  405.             z = 0;
  406.             (void) sprintf(msg + mlen, ".%ld", (long)*i);
  407.             mlen += strlen(msg + mlen);
  408.         }
  409.         message(1, msg, mlen);
  410.     }
  411. }
  412.  
  413. /*
  414.  * End a page (process a DVI_EOP).
  415.  */
  416. EndPage(really)
  417.      int really;
  418. {
  419.  
  420.     if (!UseThisPage || !really)
  421.         return;
  422.     if (!SFlag)
  423.         message(0, "]", 1);
  424.     putbyte(outf, DVI_EOP);
  425.     if (ferror(outf))
  426.         error(1, -1, writeerr);
  427.     CurrentPosition++;
  428.     NumberOfOutputPages++;
  429. }
  430.  
  431. /*
  432.  * For each of the fonts used in the new DVI file, write out a definition.
  433.  */
  434. /* ARGSUSED */
  435. void
  436. PostAmbleFontEnumerator(addr, key)
  437.     char *addr;
  438.     i32 key;
  439. {
  440.  
  441.     if (((struct fontinfo *)addr)->fi_reallyused)
  442.         WriteFont((struct fontinfo *)addr);
  443. }
  444.  
  445. HandlePostAmble()
  446. {
  447.     register i32 c;
  448.  
  449.     (void) GetLong(inf);    /* previous page pointer */
  450.     if (GetLong(inf) != Numerator)
  451.         GripeMismatchedValue("numerator");
  452.     if (GetLong(inf) != Denominator)
  453.         GripeMismatchedValue("denominator");
  454.     if (GetLong(inf) * Magnification / 1000 != DVIMag)
  455.         GripeMismatchedValue("\\magnification");
  456.  
  457.     putbyte(outf, DVI_POST);
  458.     PutLong(outf, StartOfLastPage);
  459.     PutLong(outf, Numerator);
  460.     PutLong(outf, Denominator);
  461.     PutLong(outf, DVIMag);
  462.     c = GetLong(inf);
  463.     PutLong(outf, c);    /* tallest page height */
  464.     c = GetLong(inf);
  465.     PutLong(outf, c);    /* widest page width */
  466.     c = GetWord(inf)+1;
  467.     PutWord(outf, c);    /* DVI stack size */
  468.     PutWord(outf, NumberOfOutputPages);
  469.     StartOfLastPage = CurrentPosition;    /* point at post */
  470.     CurrentPosition += 29;    /* count all those `put's */
  471. #ifdef notdef
  472.     (void) GetWord(inf);    /* skip original number of pages */
  473. #endif
  474.  
  475.     /*
  476.      * just ignore all the incoming font definitions; we are done with
  477.      * input file 
  478.      */
  479.  
  480.     /*
  481.      * run through the FontFinder table and dump definitions for the
  482.      * fonts we have used. 
  483.      */
  484.     SEnumerate(FontFinder, PostAmbleFontEnumerator);
  485.  
  486.     putbyte(outf, DVI_POSTPOST);
  487.     PutLong(outf, StartOfLastPage);    /* actually start of postamble */
  488.     putbyte(outf, DVI_VERSION);
  489.     putbyte(outf, DVI_FILLER);
  490.     putbyte(outf, DVI_FILLER);
  491.     putbyte(outf, DVI_FILLER);
  492.     putbyte(outf, DVI_FILLER);
  493.     CurrentPosition += 10;
  494.     while (CurrentPosition & 3) {
  495.         putbyte(outf, DVI_FILLER);
  496.         CurrentPosition++;
  497.     }
  498.     if (ferror(outf))
  499.         error(1, -1, writeerr);
  500. }
  501.  
  502. /*
  503.  * Write a font definition to the output file
  504.  */
  505. WriteFont(fi)
  506.     register struct fontinfo *fi;
  507. {
  508.     register int l;
  509.     register char *s;
  510.  
  511.     if (fi->fi_newindex < 256) {
  512.         putbyte(outf, DVI_FNTDEF1);
  513.         putbyte(outf, fi->fi_newindex);
  514.         CurrentPosition += 2;
  515.     } else if (fi->fi_newindex < 65536) {
  516.         putbyte(outf, DVI_FNTDEF2);
  517.         PutWord(outf, fi->fi_newindex);
  518.         CurrentPosition += 3;
  519.     } else if (fi->fi_newindex < 16777216) {
  520.         putbyte(outf, DVI_FNTDEF3);
  521.         Put3Byte(outf, fi->fi_newindex);
  522.         CurrentPosition += 4;
  523.     } else {
  524.         putbyte(outf, DVI_FNTDEF4);
  525.         PutLong(outf, fi->fi_newindex);
  526.         CurrentPosition += 5;
  527.     }
  528.     PutLong(outf, fi->fi_checksum);
  529.     PutLong(outf, fi->fi_mag);
  530.     PutLong(outf, fi->fi_designsize);
  531.     putbyte(outf, fi->fi_n1);
  532.     putbyte(outf, fi->fi_n2);
  533.     l = fi->fi_n1 + fi->fi_n2;
  534.     CurrentPosition += 14 + l;
  535.     s = fi->fi_name;
  536.     while (--l >= 0)
  537.         putbyte(outf, *s++);
  538. }
  539.  
  540. /*
  541.  * Handle the preamble.  Someday we should update the comment field.
  542.  */
  543. HandlePreAmble()
  544. {
  545.     register int n, c;
  546.  
  547.     c = getc(inf);
  548.     if (c == EOF)
  549.         GripeUnexpectedDVIEOF();
  550.     if (c != DVI_PRE)
  551.         GripeMissingOp("PRE");
  552.     if (getc(inf) != DVI_VERSION)
  553.         error(1, 0, "%s is not a DVI version %d file",
  554.             DVIFileName, DVI_VERSION);
  555.     Numerator = GetLong(inf);
  556.     Denominator = GetLong(inf);
  557.     DVIMag = GetLong(inf) * Magnification / 1000;
  558.     putbyte(outf, DVI_PRE);
  559.     putbyte(outf, DVI_VERSION);
  560.     PutLong(outf, Numerator);
  561.     PutLong(outf, Denominator);
  562.     PutLong(outf, DVIMag);
  563.  
  564.     n = UnSign8(GetByte(inf));
  565.     CurrentPosition = 15 + n;    /* well, almost */
  566.     putbyte(outf, n);
  567.     while (--n >= 0) {
  568.         c = GetByte(inf);
  569.         putbyte(outf, c);
  570.     }
  571. }
  572.  
  573. main(argc, argv)
  574.     int argc;
  575.     register char **argv;
  576. {
  577.     register int c;
  578.     register char *s;
  579.     char *outname = NULL;
  580.     char *specstring = NULL;
  581.  
  582.     Width = 0;
  583.     Height = 0;
  584.     Magnification = 1000;
  585.     Modulo = 1;
  586.  
  587.     ProgName = *argv;
  588.     setbuf(stderr, serrbuf);
  589.  
  590.     while ((c = getopt(argc, argv, "i:o:w:h:q")) != EOF) {
  591.         switch (c) {
  592.  
  593.         case 'q':    /* silent */
  594.             SFlag++;
  595.             break;
  596.  
  597.         case 'i':
  598.             if (DVIFileName != NULL)
  599.                 goto usage;
  600.             DVIFileName = optarg;
  601.             break;
  602.  
  603.         case 'o':
  604.             if (outname != NULL)
  605.                 goto usage;
  606.             outname = optarg;
  607.             break;
  608.  
  609.         case 'w':
  610.             if (Width != 0)
  611.                 goto usage;
  612.             Width = singledimen(optarg);
  613.             if (Width <= 0)
  614.                error(1, -1, "-w parameter must be > 0");
  615.             break;
  616.  
  617.         case 'h':
  618.             if (Height != 0)
  619.                 goto usage;
  620.             Height = singledimen(optarg);
  621.             if (Height <= 0)
  622.                error(1, -1, "-h parameter must be > 0");
  623.             break;
  624.  
  625.         case '?':
  626. usage:
  627.             (void) fprintf(stderr, "\
  628. Usage: %s [-q] [-i infile] [-o outfile] [-w width] [-h height] <pagespecs> [infile [outfile]]\n",
  629.                 ProgName);
  630.             (void) fflush(stderr);
  631.             exit(1);
  632.         }
  633.     }
  634.  
  635.     while (optind < argc) {
  636.         s = argv[optind++];
  637.         c = *s;
  638.         if (specstring == NULL)
  639.                 (void) ParseSpecs((specstring = s), 0);
  640.         else if (DVIFileName == NULL)
  641.             DVIFileName = s;
  642.         else if (outname == NULL)
  643.             outname = s;
  644.         else
  645.             goto usage;
  646.     }
  647.  
  648.     if (specstring == NULL)
  649.             goto usage;
  650.  
  651.     if (DVIFileName == NULL) {
  652.         DVIFileName = "`stdin'";
  653.         inf = stdin;
  654.     } else if ((inf = fopen(DVIFileName, "r")) == 0)
  655.         error(1, -1, "cannot read %s", DVIFileName);
  656.     if (outname == NULL)
  657.         outf = stdout;
  658.     else if ((outf = fopen(outname, "w")) == 0)
  659.         error(1, -1, "cannot write %s", outname);
  660.  
  661.     if ((FontFinder = SCreate(sizeof(struct fontinfo))) == 0)
  662.         error(1, 0, "cannot create font finder (out of memory?)");
  663.  
  664.     /* copy inf to TEMP file if not seekable */
  665.     if ((inf = SeekFile(inf)) == NULL) {
  666.             error(1, 0, "can't seek file");
  667.     }
  668.  
  669.     InputPageNumber = 0;
  670.     StartOfLastPage = -1;
  671.     HandlePreAmble();
  672.     ScanDVIFile();
  673.     if (fseek(inf, 16L, 1) == -1)
  674.             error(1, -1, "can't seek postamble");
  675.     if (Height == 0)         /* get height from postamble */
  676.        Height = GetLong(inf);
  677.     else
  678.        (void) GetLong(inf); /* ignore height */
  679.     if (Width == 0)          /* get width from postamble */
  680.        Width = GetLong(inf);
  681.     PageSpecs = ParseSpecs(specstring, 1);
  682.  
  683.     HandleDVIFile();
  684.     HandlePostAmble();
  685.     if (!SFlag)
  686.         (void) fprintf(stderr, "\nWrote %d page%s, %ld bytes\n",
  687.             NumberOfOutputPages, NumberOfOutputPages == 1 ? "" : "s",
  688.             (long)CurrentPosition);
  689.     exit(0);
  690.     /* NOTREACHED */
  691. }
  692.  
  693. /*
  694.  * Handle a font definition.
  695.  */
  696. HandleFontDef(index)
  697.     i32 index;
  698. {
  699.     register struct fontinfo *fi;
  700.     register int i;
  701.     register char *s;
  702.     int def = S_CREATE | S_EXCL;
  703.  
  704.     if (!UseThisPage) {
  705.         if ((fi = (struct fontinfo *)SSearch(FontFinder, index, &def)) == 0)
  706.             if (def & S_COLL)
  707.                 error(1, 0, "font %ld already defined", (long)index);
  708.             else
  709.                 error(1, 0, "cannot stash font %ld (out of memory?)",
  710.                     (long)index);
  711.         fi->fi_reallyused = 0;
  712.         fi->fi_checksum = GetLong(inf);
  713.         fi->fi_mag = GetLong(inf);
  714.         fi->fi_designsize = GetLong(inf);
  715.         fi->fi_n1 = UnSign8(GetByte(inf));
  716.         fi->fi_n2 = UnSign8(GetByte(inf));
  717.         i = fi->fi_n1 + fi->fi_n2;
  718.         if ((s = malloc((unsigned)i)) == 0)
  719.             GripeOutOfMemory(i, "font name");
  720.         fi->fi_name = s;
  721.         while (--i >= 0)
  722.             *s++ = GetByte(inf);
  723.     } else {
  724.             (void) GetLong(inf);
  725.             (void) GetLong(inf);
  726.             (void) GetLong(inf);
  727.         i = UnSign8(GetByte(inf));
  728.         i += UnSign8(GetByte(inf));
  729.         while (--i >= 0)
  730.             (void) GetByte(inf);
  731.     }
  732. }
  733.  
  734. /*
  735.  * Handle a \special.
  736.  */
  737. HandleSpecial(c, l, p)
  738.     int c;
  739.     register int l;
  740.     register i32 p;
  741. {
  742.     register int i;
  743.  
  744.     if (UseThisPage) {
  745.         putbyte(outf, c);
  746.         switch (l) {
  747.  
  748.         case DPL_UNS1:
  749.             putbyte(outf, p);
  750.             CurrentPosition += 2;
  751.             break;
  752.  
  753.         case DPL_UNS2:
  754.             PutWord(outf, p);
  755.             CurrentPosition += 3;
  756.             break;
  757.  
  758.         case DPL_UNS3:
  759.             Put3Byte(outf, p);
  760.             CurrentPosition += 4;
  761.             break;
  762.  
  763.         case DPL_SGN4:
  764.             PutLong(outf, p);
  765.             CurrentPosition += 5;
  766.             break;
  767.  
  768.         default:
  769.             panic("HandleSpecial l=%d", l);
  770.             /* NOTREACHED */
  771.         }
  772.         CurrentPosition += p;
  773.         while (--p >= 0) {
  774.             i = getc(inf);
  775.             putbyte(outf, i);
  776.         }
  777.         if (feof(inf))
  778.             GripeUnexpectedDVIEOF();
  779.         if (ferror(outf))
  780.             error(1, -1, writeerr);
  781.     } else
  782.         while (--p >= 0)
  783.             (void) getc(inf);
  784. }
  785.  
  786. ReallyUseFont()
  787. {
  788.     register struct fontinfo *fi;
  789.     int look = S_LOOKUP;
  790.  
  791.     fi = (struct fontinfo *)SSearch(FontFinder, CurrentFontIndex, &look);
  792.     if (fi == NULL)
  793.         error(1, 0, "DVI file requested font %ld without defining it",
  794.             (long)CurrentFontIndex);
  795.     if (fi->fi_reallyused == 0) {
  796.         fi->fi_reallyused++;
  797.         fi->fi_newindex = NextOutputFontIndex++;
  798.         WriteFont(fi);
  799.     }
  800.     if (fi->fi_newindex != OutputFontIndex) {
  801.         PutFontSelector(fi->fi_newindex);
  802.         OutputFontIndex = fi->fi_newindex;
  803.     }
  804. }
  805.  
  806. /*
  807.  * Write a font selection command to the output file
  808.  */
  809. PutFontSelector(index)
  810.     i32 index;
  811. {
  812.  
  813.     if (index < 64) {
  814.         putbyte(outf, index + DVI_FNTNUM0);
  815.         CurrentPosition++;
  816.     } else if (index < 256) {
  817.         putbyte(outf, DVI_FNT1);
  818.         putbyte(outf, index);
  819.         CurrentPosition += 2;
  820.     } else if (index < 65536) {
  821.         putbyte(outf, DVI_FNT2);
  822.         PutWord(outf, index);
  823.         CurrentPosition += 3;
  824.     } else if (index < 16777216) {
  825.         putbyte(outf, DVI_FNT3);
  826.         Put3Byte(outf, index);
  827.         CurrentPosition += 4;
  828.     } else {
  829.         putbyte(outf, DVI_FNT4);
  830.         PutLong(outf, index);
  831.         CurrentPosition += 5;
  832.     }
  833. }
  834.  
  835. /*
  836.  * The following table describes the length (in bytes) of each of the DVI
  837.  * commands that we can simply copy, starting with DVI_SET1 (128).
  838.  */
  839. char    oplen[128] = {
  840.     0, 0, 0, 0,        /* DVI_SET1 .. DVI_SET4 */
  841.     9,            /* DVI_SETRULE */
  842.     0, 0, 0, 0,        /* DVI_PUT1 .. DVI_PUT4 */
  843.     9,            /* DVI_PUTRULE */
  844.     1,            /* DVI_NOP */
  845.     0,            /* DVI_BOP */
  846.     0,            /* DVI_EOP */
  847.     1,            /* DVI_PUSH */
  848.     1,            /* DVI_POP */
  849.     2, 3, 4, 5,        /* DVI_RIGHT1 .. DVI_RIGHT4 */
  850.     1,            /* DVI_W0 */
  851.     2, 3, 4, 5,        /* DVI_W1 .. DVI_W4 */
  852.     1,            /* DVI_X0 */
  853.     2, 3, 4, 5,        /* DVI_X1 .. DVI_X4 */
  854.     2, 3, 4, 5,        /* DVI_DOWN1 .. DVI_DOWN4 */
  855.     1,            /* DVI_Y0 */
  856.     2, 3, 4, 5,        /* DVI_Y1 .. DVI_Y4 */
  857.     1,            /* DVI_Z0 */
  858.     2, 3, 4, 5,        /* DVI_Z1 .. DVI_Z4 */
  859.     0,            /* DVI_FNTNUM0 (171) */
  860.     0, 0, 0, 0, 0, 0, 0, 0,    /* 172 .. 179 */
  861.     0, 0, 0, 0, 0, 0, 0, 0,    /* 180 .. 187 */
  862.     0, 0, 0, 0, 0, 0, 0, 0,    /* 188 .. 195 */
  863.     0, 0, 0, 0, 0, 0, 0, 0,    /* 196 .. 203 */
  864.     0, 0, 0, 0, 0, 0, 0, 0,    /* 204 .. 211 */
  865.     0, 0, 0, 0, 0, 0, 0, 0,    /* 212 .. 219 */
  866.     0, 0, 0, 0, 0, 0, 0, 0,    /* 220 .. 227 */
  867.     0, 0, 0, 0, 0, 0, 0,    /* 228 .. 234 */
  868.     0, 0, 0, 0,        /* DVI_FNT1 .. DVI_FNT4 */
  869.     0, 0, 0, 0,        /* DVI_XXX1 .. DVI_XXX4 */
  870.     0, 0, 0, 0,        /* DVI_FNTDEF1 .. DVI_FNTDEF4 */
  871.     0,            /* DVI_PRE */
  872.     0,            /* DVI_POST */
  873.     0,            /* DVI_POSTPOST */
  874.     0, 0, 0, 0, 0, 0,    /* 250 .. 255 */
  875. };
  876.  
  877. int
  878. HandlePage(first, last, hoffset, voffset)
  879.      int first, last;
  880.      i32 hoffset, voffset;
  881. {
  882.     register int c, l;
  883.     register i32 p;
  884.     register int CurrentFontOK = 0;
  885.     int doingpage = 0;
  886.  
  887.     /* Only way out is via "return" statement */
  888.     for (;;) {
  889.         c = getc(inf);    /* getc() returns unsigned values */
  890.         if (DVI_IsChar(c)) {
  891.             /*
  892.              * Copy chars, note font usage, but ignore if
  893.              * page is not interesting.
  894.              */
  895.             if (!UseThisPage)
  896.                 continue;
  897.             if (!CurrentFontOK) {
  898.                 ReallyUseFont();
  899.                 CurrentFontOK++;
  900.             }
  901.             putbyte(outf, c);
  902.             CurrentPosition++;
  903.             continue;
  904.         }
  905.         if (DVI_IsFont(c)) {    /* note font change */
  906.             CurrentFontIndex = c - DVI_FNTNUM0;
  907.             CurrentFontOK = 0;
  908.             continue;
  909.         }
  910.         if (c == EOF)
  911.             GripeUnexpectedDVIEOF();
  912.         if ((l = (oplen - 128)[c]) != 0) {    /* simple copy */
  913.             if (!UseThisPage) {
  914.                 while (--l > 0)
  915.                     (void) getc(inf);
  916.                 continue;
  917.             }
  918.             CurrentPosition += l;
  919.             putbyte(outf, c);
  920.             while (--l > 0) {
  921.                 c = getc(inf);
  922.                 putbyte(outf, c);
  923.             }
  924.             if (ferror(outf))
  925.                 error(1, -1, writeerr);
  926.             continue;
  927.         }
  928.         if ((l = DVI_OpLen(c)) != 0) {
  929.             /*
  930.              * Handle other generics.
  931.              * N.B.: there should only be unsigned parameters
  932.              * here (save SGN4), for commands with negative
  933.              * parameters have been taken care of above.
  934.              */
  935.             switch (l) {
  936.  
  937.             case DPL_UNS1:
  938.                 p = getc(inf);
  939.                 break;
  940.  
  941.             case DPL_UNS2:
  942.                 fGetWord(inf, p);
  943.                 break;
  944.  
  945.             case DPL_UNS3:
  946.                 fGet3Byte(inf, p);
  947.                 break;
  948.  
  949.             case DPL_SGN4:
  950.                 fGetLong(inf, p);
  951.                 break;
  952.  
  953.             default:
  954.                 panic("HandleDVIFile l=%d", l);
  955.             }
  956.  
  957.             /*
  958.              * Now that we have the parameter, perform the
  959.              * command.
  960.              */
  961.             switch (DVI_DT(c)) {
  962.  
  963.             case DT_SET:
  964.             case DT_PUT:
  965.                 if (!UseThisPage)
  966.                     continue;
  967.                 if (!CurrentFontOK) {
  968.                     ReallyUseFont();
  969.                     CurrentFontOK++;
  970.                 }
  971.                 putbyte(outf, c);
  972.                 switch (l) {
  973.  
  974.                 case DPL_UNS1:
  975.                     putbyte(outf, p);
  976.                     CurrentPosition += 2;
  977.                     continue;
  978.  
  979.                 case DPL_UNS2:
  980.                     PutWord(outf, p);
  981.                     CurrentPosition += 3;
  982.                     continue;
  983.  
  984.                 case DPL_UNS3:
  985.                     Put3Byte(outf, p);
  986.                     CurrentPosition += 4;
  987.                     continue;
  988.  
  989.                 case DPL_SGN4:
  990.                     PutLong(outf, p);
  991.                     CurrentPosition += 5;
  992.                     continue;
  993.                 }
  994.  
  995.             case DT_FNT:
  996.                 CurrentFontIndex = p;
  997.                 CurrentFontOK = 0;
  998.                 continue;
  999.  
  1000.             case DT_XXX:
  1001.                 HandleSpecial(c, l, p);
  1002.                 continue;
  1003.  
  1004.             case DT_FNTDEF:
  1005.                 HandleFontDef(p);
  1006.                 continue;
  1007.  
  1008.             default:
  1009.                 panic("HandleDVIFile DVI_DT(%d)=%d",
  1010.                       c, DVI_DT(c));
  1011.             }
  1012.             continue;
  1013.         }
  1014.  
  1015.         switch (c) {    /* handle the few remaining cases */
  1016.  
  1017.         case DVI_BOP:
  1018.             if (doingpage)
  1019.                 GripeUnexpectedOp("BOP (during page)");
  1020.             BeginPage(first);
  1021.             if (UseThisPage) {
  1022.                if (!last) {
  1023.                   putbyte(outf, DVI_PUSH);
  1024.                   CurrentPosition++;
  1025.                }
  1026.                if (hoffset != 0) {
  1027.                   putbyte(outf, DVI_RIGHT4) ;
  1028.                   PutLong(outf, hoffset) ;
  1029.                   CurrentPosition += 5;
  1030.                }
  1031.                if (voffset != 0) {
  1032.                   putbyte(outf, DVI_DOWN4) ;
  1033.                   PutLong(outf, voffset) ;
  1034.                   CurrentPosition += 5;
  1035.                }
  1036.             }
  1037.             doingpage = 1;
  1038.             break;
  1039.  
  1040.         case DVI_EOP:
  1041.             if (!doingpage)
  1042.                 GripeUnexpectedOp("EOP (outside page)");
  1043.             if (!last && UseThisPage) {
  1044.                putbyte(outf, DVI_POP);
  1045.                CurrentPosition++;
  1046.             }
  1047.             EndPage(last);
  1048.             doingpage = 0;
  1049.             return(1);
  1050.  
  1051.         case DVI_PRE:
  1052.             GripeUnexpectedOp("PRE");
  1053.             /* NOTREACHED */
  1054.  
  1055.         case DVI_POST:
  1056.             if (doingpage)
  1057.                 GripeUnexpectedOp("POST (inside page)");
  1058.             return(0);
  1059.  
  1060.         case DVI_POSTPOST:
  1061.             GripeUnexpectedOp("POSTPOST");
  1062.             /* NOTREACHED */
  1063.  
  1064.         default:
  1065.             GripeUndefinedOp(c);
  1066.             /* NOTREACHED */
  1067.         }
  1068.     }
  1069. }
  1070.  
  1071. /* write an empty page to fill out space */
  1072. PutEmptyPage()
  1073. {
  1074.         int i;
  1075.  
  1076.     putbyte(outf, DVI_BOP);
  1077.     PutLong(outf, -1L);
  1078.     for (i = 1; i < 10; i++)     /* set all sub counts to 0 */
  1079.         PutLong(outf, 0L);
  1080.     PutLong(outf, StartOfLastPage);
  1081.     putbyte(outf, DVI_EOP);
  1082.     if (!SFlag) {        /* write nice page usage messages */
  1083.         char *msg = "[*]";
  1084.         message(1, msg, strlen(msg));
  1085.     }
  1086.     if (ferror(outf))
  1087.         error(1, -1, writeerr);
  1088.  
  1089.     StartOfLastPage = CurrentPosition;
  1090.     CurrentPosition += 46;    /* we just wrote this much */
  1091.     NumberOfOutputPages++;
  1092. }
  1093.  
  1094. /*
  1095.  * Here we scan the input DVI file and record pointers to the pages.
  1096.  */
  1097. ScanDVIFile()
  1098. {
  1099.     UseThisPage = 0;
  1100.  
  1101.     StartOfPage[InputPageNumber] = ftell(inf);
  1102.     while (HandlePage(0, 0, 0, 0)) {  /* scan DVI file */
  1103.             StartOfPage[++InputPageNumber] = ftell(inf);
  1104.     }
  1105. }
  1106.  
  1107. /*
  1108.  * Here we read the input DVI file and write relevant pages to the
  1109.  * output DVI file. We also keep track of font changes, handle font
  1110.  * definitions, and perform some other housekeeping.
  1111.  */
  1112. HandleDVIFile()
  1113. {
  1114.         int CurrentPage, ActualPage, MaxPage;
  1115.  
  1116.     UseThisPage = 1;
  1117.  
  1118.     MaxPage = ((InputPageNumber+Modulo-1)/Modulo)*Modulo;
  1119.  
  1120.     for (CurrentPage = 0; CurrentPage < MaxPage; CurrentPage += Modulo) {
  1121.        int add_last = 0;
  1122.        struct pagespec *ps;
  1123.        for (ps = PageSpecs; ps != NULL; ps = ps->next) {
  1124.           int add_next = ps->add;
  1125.           if (ps->reversed)
  1126.          ActualPage = MaxPage-CurrentPage-Modulo+ps->pageno;
  1127.           else
  1128.          ActualPage = CurrentPage+ps->pageno;
  1129.           if (ActualPage < InputPageNumber) {
  1130.          if (fseek(inf, StartOfPage[ActualPage], 0) == -1)
  1131.             error(1, -1,
  1132.               "can't seek page %d", ActualPage+1);
  1133.                 HandlePage(!add_last, !add_next, ps->xoff, ps->yoff);
  1134.           } else if (!add_last && !add_next)
  1135.                         PutEmptyPage();
  1136.           add_last = add_next;
  1137.        }
  1138.     }
  1139.     if (fseek(inf, StartOfPage[InputPageNumber]+1, 0) == -1)
  1140.             error(1, -1, "can't seek last page");
  1141. }
  1142.